#include "common_data.h"

static const uint16_t acu16S_Talbe[256U] =
{
  0x0000U, 0xC0C1U, 0xC181U, 0x0140U, 0xC301U, 0x03C0U, 0x0280U, 0xC241U,
  0xC601U, 0x06C0U, 0x0780U, 0xC741U, 0x0500U, 0xC5C1U, 0xC481U, 0x0440U,
  0xCC01U, 0x0CC0U, 0x0D80U, 0xCD41U, 0x0F00U, 0xCFC1U, 0xCE81U, 0x0E40U,
  0x0A00U, 0xCAC1U, 0xCB81U, 0x0B40U, 0xC901U, 0x09C0U, 0x0880U, 0xC841U,
  0xD801U, 0x18C0U, 0x1980U, 0xD941U, 0x1B00U, 0xDBC1U, 0xDA81U, 0x1A40U,
  0x1E00U, 0xDEC1U, 0xDF81U, 0x1F40U, 0xDD01U, 0x1DC0U, 0x1C80U, 0xDC41U,
  0x1400U, 0xD4C1U, 0xD581U, 0x1540U, 0xD701U, 0x17C0U, 0x1680U, 0xD641U,
  0xD201U, 0x12C0U, 0x1380U, 0xD341U, 0x1100U, 0xD1C1U, 0xD081U, 0x1040U,
  0xF001U, 0x30C0U, 0x3180U, 0xF141U, 0x3300U, 0xF3C1U, 0xF281U, 0x3240U,
  0x3600U, 0xF6C1U, 0xF781U, 0x3740U, 0xF501U, 0x35C0U, 0x3480U, 0xF441U,
  0x3C00U, 0xFCC1U, 0xFD81U, 0x3D40U, 0xFF01U, 0x3FC0U, 0x3E80U, 0xFE41U,
  0xFA01U, 0x3AC0U, 0x3B80U, 0xFB41U, 0x3900U, 0xF9C1U, 0xF881U, 0x3840U,
  0x2800U, 0xE8C1U, 0xE981U, 0x2940U, 0xEB01U, 0x2BC0U, 0x2A80U, 0xEA41U,
  0xEE01U, 0x2EC0U, 0x2F80U, 0xEF41U, 0x2D00U, 0xEDC1U, 0xEC81U, 0x2C40U,
  0xE401U, 0x24C0U, 0x2580U, 0xE541U, 0x2700U, 0xE7C1U, 0xE681U, 0x2640U,
  0x2200U, 0xE2C1U, 0xE381U, 0x2340U, 0xE101U, 0x21C0U, 0x2080U, 0xE041U,
  0xA001U, 0x60C0U, 0x6180U, 0xA141U, 0x6300U, 0xA3C1U, 0xA281U, 0x6240U,
  0x6600U, 0xA6C1U, 0xA781U, 0x6740U, 0xA501U, 0x65C0U, 0x6480U, 0xA441U,
  0x6C00U, 0xACC1U, 0xAD81U, 0x6D40U, 0xAF01U, 0x6FC0U, 0x6E80U, 0xAE41U,
  0xAA01U, 0x6AC0U, 0x6B80U, 0xAB41U, 0x6900U, 0xA9C1U, 0xA881U, 0x6840U,
  0x7800U, 0xB8C1U, 0xB981U, 0x7940U, 0xBB01U, 0x7BC0U, 0x7A80U, 0xBA41U,
  0xBE01U, 0x7EC0U, 0x7F80U, 0xBF41U, 0x7D00U, 0xBDC1U, 0xBC81U, 0x7C40U,
  0xB401U, 0x74C0U, 0x7580U, 0xB541U, 0x7700U, 0xB7C1U, 0xB681U, 0x7640U,
  0x7200U, 0xB2C1U, 0xB381U, 0x7340U, 0xB101U, 0x71C0U, 0x7080U, 0xB041U,
  0x5000U, 0x90C1U, 0x9181U, 0x5140U, 0x9301U, 0x53C0U, 0x5280U, 0x9241U,
  0x9601U, 0x56C0U, 0x5780U, 0x9741U, 0x5500U, 0x95C1U, 0x9481U, 0x5440U,
  0x9C01U, 0x5CC0U, 0x5D80U, 0x9D41U, 0x5F00U, 0x9FC1U, 0x9E81U, 0x5E40U,
  0x5A00U, 0x9AC1U, 0x9B81U, 0x5B40U, 0x9901U, 0x59C0U, 0x5880U, 0x9841U,
  0x8801U, 0x48C0U, 0x4980U, 0x8941U, 0x4B00U, 0x8BC1U, 0x8A81U, 0x4A40U,
  0x4E00U, 0x8EC1U, 0x8F81U, 0x4F40U, 0x8D01U, 0x4DC0U, 0x4C80U, 0x8C41U,
  0x4400U, 0x84C1U, 0x8581U, 0x4540U, 0x8701U, 0x47C0U, 0x4680U, 0x8641U,
  0x8201U, 0x42C0U, 0x4380U, 0x8341U, 0x4100U, 0x81C1U, 0x8081U, 0x4040U,
};

/**************************************************************************
*\brief        CRC-16/IBM 校验算法,多项式 X16+X15+X2+1
*\param [in]   acu8I_Crc16Buf 原始数据
*\param [in]   u16I_Crc16Len  数据长度
*\param [out]  无
*\retval       CRC16校验值
*************************************************************************/
uint16_t x_Crc16Check(const uint8_t *acu8I_Crc16Buf, uint16_t u16I_Crc16Len)
{
  uint16_t u16T_Crc16Value = 0xFFFFU;
  uint8_t  u8T_Crc16Index  = 0U;
  uint16_t u16T_Crc16Cnt   = 0U;
  uint16_t u16T_Crc16Len   = u16I_Crc16Len;

  if(acu8I_Crc16Buf != NULL)
  {
    while (u16T_Crc16Len > 0U)
    {
      u16T_Crc16Len--;

      /* 根据当前数据获取下标 */
      u8T_Crc16Index =
        (uint8_t)((u16T_Crc16Value & 0xFFU) ^ (acu8I_Crc16Buf[u16T_Crc16Cnt]));

      /* 根据下标查表计算CRC16 */
      u16T_Crc16Value =
        (uint16_t)((uint16_t)(u16T_Crc16Value >> 8U) ^ acu16S_Talbe[u8T_Crc16Index]);

      u16T_Crc16Cnt++;
    }
  }
  else
  {
    /* Do Nothing */
  }

  /* 返回CRC16计算结果，调整大小端 */
  //return u16T_Crc16Value;
  return  (u16T_Crc16Value << 8) | (u16T_Crc16Value >> 8);
}

//上电后加载配置参数初始化数据文件，如果没有，则创建，同时赋予结构体初始值
void LoadAdjustParameter()
{
    QFile file(CFG_FILE_PATH);

    if(file.exists())
    {
        qDebug() << "Load Parameter!";
        //读取ini配置文件
        QSettings *settings = new QSettings(CFG_FILE_PATH, QSettings::IniFormat);

        common_data::init_config_param.oven_temperature = settings->value("Project/oven_temperature").toDouble();
        common_data::init_config_param.sample_time = settings->value("Project/sample_time").toDouble();
        common_data::init_config_param.reserve_time = settings->value("Project/reserve_time").toUInt();
        common_data::init_config_param.fluctuation_threshold = settings->value("Project/fluctuation_threshold").toDouble();
        common_data::init_config_param.pid_lamp_voltage = settings->value("Project/pid_lamp_voltage").toUInt();
        common_data::init_config_param.detector_temperature = settings->value("Project/detector_temperature").toDouble();
        common_data::init_config_param.carrier_gas = settings->value("Project/carrier_gas").toDouble();
        common_data::init_config_param.offset_time = settings->value("Project/offset_time").toUInt();
        common_data::init_config_param.filter_window = settings->value("Project/filter_window").toUInt();
        common_data::init_config_param.analysis_duration = settings->value("Project/analysis_duration").toUInt();
        common_data::init_config_param.deviceId = settings->value("Project/deviceId").toString();
        common_data::init_config_param.gas_name_index = settings->value("Project/gas_name_index").toUInt();
        common_data::init_config_param.gas_unit_index = settings->value("Project/gas_unit_index").toUInt();
        common_data::init_config_param.power_supply_index = settings->value("Project/power_supply_index").toUInt();
        common_data::init_config_param.baud_index = settings->value("Project/baud_index").toUInt();
        common_data::init_config_param.detect_mode_index = settings->value("Project/detect_mode_index").toUInt();
        common_data::init_config_param.loop_detect_time = settings->value("Project/loop_detect_time").toUInt();
        common_data::init_config_param.detect_time_1_hour = settings->value("Project/detect_time_1_hour").toUInt();
        common_data::init_config_param.detect_time_1_min = settings->value("Project/detect_time_1_min").toUInt();
        common_data::init_config_param.detect_time_1_open_flag = settings->value("Project/detect_time_1_open_flag").toBool();
        common_data::init_config_param.detect_time_2_hour = settings->value("Project/detect_time_2_hour").toUInt();
        common_data::init_config_param.detect_time_2_min = settings->value("Project/detect_time_2_min").toUInt();
        common_data::init_config_param.detect_time_2_open_flag = settings->value("Project/detect_time_2_open_flag").toBool();
        common_data::init_config_param.detect_time_3_hour = settings->value("Project/detect_time_3_hour").toUInt();
        common_data::init_config_param.detect_time_3_min = settings->value("Project/detect_time_3_min").toUInt();
        common_data::init_config_param.detect_time_3_open_flag = settings->value("Project/detect_time_3_open_flag").toBool();
        common_data::init_config_param.sleep_mode_open_flag = settings->value("Project/sleep_mode_open_flag").toBool();
        common_data::init_config_param.dev_software_version = settings->value("Project/dev_software_version").toString();
        common_data::init_config_param.dev_hardware_version = settings->value("Project/dev_hardware_version").toString();

        delete settings;
    }
    else
    {
        file.open( QIODevice::ReadWrite | QIODevice::Text);
        file.close();   //注意关闭文件

        QSettings *settings = new QSettings(CFG_FILE_PATH, QSettings::IniFormat);

        // 以键值对的形式写入数据
        settings->setValue("Project/oven_temperature", common_data::init_config_param.oven_temperature);              //柱箱温度
        settings->setValue("Project/sample_time", common_data::init_config_param.sample_time);                 //采样时间
        settings->setValue("Project/reserve_time", common_data::init_config_param.reserve_time);                //保留时间
        settings->setValue("Project/fluctuation_threshold", common_data::init_config_param.fluctuation_threshold);      //波动阈值
        settings->setValue("Project/pid_lamp_voltage", common_data::init_config_param.pid_lamp_voltage);             //UV灯电压
        settings->setValue("Project/detector_temperature", common_data::init_config_param.detector_temperature);        //检测器温度
        settings->setValue("Project/carrier_gas", common_data::init_config_param.carrier_gas);                 //载气压力
        settings->setValue("Project/offset_time", common_data::init_config_param.offset_time);                 //偏移时间
        settings->setValue("Project/filter_window", common_data::init_config_param.filter_window);               //滤波窗口
        settings->setValue("Project/analysis_duration", common_data::init_config_param.analysis_duration);

        settings->setValue("Project/deviceId", common_data::init_config_param.deviceId);
        settings->setValue("Project/gas_name_index", common_data::init_config_param.gas_name_index);
        settings->setValue("Project/gas_unit_index", common_data::init_config_param.gas_unit_index);
        settings->setValue("Project/power_supply_index", common_data::init_config_param.power_supply_index);
        settings->setValue("Project/baud_index", common_data::init_config_param.baud_index);
        settings->setValue("Project/detect_mode_index", common_data::init_config_param.detect_mode_index);
        settings->setValue("Project/loop_detect_time", common_data::init_config_param.loop_detect_time);

        settings->setValue("Project/detect_time_1_hour", common_data::init_config_param.detect_time_1_hour);
        settings->setValue("Project/detect_time_1_min", common_data::init_config_param.detect_time_1_min);
        settings->setValue("Project/detect_time_1_open_flag", common_data::init_config_param.detect_time_1_open_flag);
        settings->setValue("Project/detect_time_2_hour", common_data::init_config_param.detect_time_2_hour);
        settings->setValue("Project/detect_time_2_min", common_data::init_config_param.detect_time_2_min);
        settings->setValue("Project/detect_time_2_open_flag", common_data::init_config_param.detect_time_2_open_flag);
        settings->setValue("Project/detect_time_3_hour", common_data::init_config_param.detect_time_3_hour);
        settings->setValue("Project/detect_time_3_min", common_data::init_config_param.detect_time_3_min);
        settings->setValue("Project/detect_time_3_open_flag", common_data::init_config_param.detect_time_3_open_flag);
        settings->setValue("Project/sleep_mode_open_flag", common_data::init_config_param.sleep_mode_open_flag);

        settings->setValue("Project/dev_software_version", common_data::init_config_param.dev_software_version);
        settings->setValue("Project/dev_hardware_version", common_data::init_config_param.dev_hardware_version);

        delete settings;
    }
}

//执行linux命令
int sw_linux_cmd(char *cmd,char *back,int len)
{
    FILE *fp = NULL;
    int ret = 1;
    fp = popen(cmd, "r");
    if(fp == NULL)
        return -1;
    if(len > 0)
    {
        ret = fread(back,1,len,fp);
    }
    pclose(fp);
    return ret;
}

//设备上电后，需要配置GPIO口
void gpio_dev_control()
{
    char buf[1024] = {0};
    char cmd[128] = {0};
    char cmd_1[128] = {0};
    char cmd_2[128] = {0};
    char cmd_3[128] = {0};

    sprintf(cmd,"echo 23 > /sys/class/gpio/export");
    sw_linux_cmd(cmd, buf, sizeof(buf));
    sleep(1);
    sprintf(cmd_1,"echo out > /sys/class/gpio/gpio23/direction");
    sw_linux_cmd(cmd_1, buf, sizeof(buf));    
    sleep(1);

    sprintf(cmd_2,"echo 24 > /sys/class/gpio/export");
    sw_linux_cmd(cmd_2, buf, sizeof(buf));
    sleep(1);

    sprintf(cmd_3,"echo  out > /sys/class/gpio/gpio24/direction");
    sw_linux_cmd(cmd_3, buf, sizeof(buf));
    sleep(1);
}

void gpio_out1_dev_enable(uint8_t value)
{
    char buf[1024] = {0};
    char cmd[128] = {0};

    memset(buf,0,sizeof(buf));
    memset(cmd,0,sizeof(cmd));

    if(value == 0)
    {
        sprintf(cmd,"echo 0 > %s", GPIO_OUT_1_ENABLE);
        sw_linux_cmd(cmd, buf, sizeof(buf));
        common_data::gpio_out1_dev_open_flag = false;
    }
    else
    {
        sprintf(cmd,"echo 1 > %s",GPIO_OUT_1_ENABLE);
        sw_linux_cmd(cmd, buf, sizeof(buf));
        common_data::gpio_out1_dev_open_flag = true;
    }
}

void gpio_out2_dev_enable(uint8_t value)
{
    char buf[1024] = {0};
    char cmd[128] = {0};

    memset(buf,0,sizeof(buf));
    memset(cmd,0,sizeof(cmd));

    if(value == 0)
    {
        sprintf(cmd,"echo 0 > %s", GPIO_OUT_2_ENABLE);
        sw_linux_cmd(cmd, buf, sizeof(buf));
        common_data::gpio_out2_dev_open_flag = false;
    }
    else
    {
        sprintf(cmd,"echo 1 > %s",GPIO_OUT_2_ENABLE);
        sw_linux_cmd(cmd, buf, sizeof(buf));
        common_data::gpio_out2_dev_open_flag = true;
    }
}

//GPIO控制，0：关闭继电器， 1： 打开继电器
void common_data::gpio_enable_preheat(bool flag)
{
    if(flag)
    {
        if(common_data::gpio_out2_dev_open_flag == false)
        {
            qDebug() << "gpio_out2_dev open success!";
            gpio_out2_dev_enable(1);
        }

        if(common_data::gpio_out1_dev_open_flag == false)
        {
            QTimer::singleShot((260 * 1000), this, []() {
                qDebug() << "gpio_out1_dev open success!";
                gpio_out1_dev_enable(1);
            });
        }
    }
    else
    {
        emit common_data_to_uart5_signal(0);

        if(common_data::gpio_out2_dev_open_flag == true)
        {
            qDebug() << "gpio_out2_dev close success";
            gpio_out2_dev_enable(0);
        }

        QTimer::singleShot((20 * 1000), this, []() {
            if(common_data::gpio_out1_dev_open_flag == true)
            {
                qDebug() << "gpio_out1_dev close success";
                gpio_out1_dev_enable(0);
            }
        });
    }
}


void start_param_gpio_control()
{
    LoadAdjustParameter();
    gpio_dev_control();
    gpio_out1_dev_enable(0);
    gpio_out2_dev_enable(0);
}
